package com.fiberhome.app.network;

import com.fiberhome.app.network.cache.CacheBean;
import com.fiberhome.app.network.cache.CacheUtil;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;

/**
 * Created by Deed on 2018/1/29.
 */

public abstract class CacheSender implements ISender {
    private final CacheBuilder cb;

    /**
     *
     * @param cb CacheBuilder
     */
    public CacheSender(CacheBuilder cb) {
        this.cb = cb;
    }

    @Override
    public <T extends IData> IData start(Class<T> cls) {
        if (cb.cache != CacheBuilder.CACHE_ONLY) {
            CacheBean data = CacheUtil.myCache().get(cb, cls);
            if (data != null) {
                return data.getData();
            }
        } else if (cb.cache != CacheBuilder.CACHE_POWER) {
            CacheBean data = CacheUtil.myCache().get(cb, cls);
            if (data != null && !CacheUtil.myCache().checkCacheOverdue(data, cb.cacheOverdue)) {
                return data.getData();
            }
        }
        return getRemoteData(cls);
    }

    @Override
    public void startAsync(final CallBack callBack) {
        Observable observer = Observable.just(cb).filter(new Predicate<CacheBuilder>() {
            @Override
            public boolean test(@NonNull CacheBuilder builder) throws Exception {
                return builder != null;
            }
        });
        if (CacheBuilder.CACHE_NO != cb.cache) {
            observer = observer.map(new Function<CacheBuilder, CacheBean>() {
                @Override
                public CacheBean apply(@NonNull CacheBuilder builder) throws Exception {
                    return CacheUtil.myCache().get(builder, callBack.getEntityClass());
                }
            }).flatMap(new Function<CacheBean, ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(@NonNull final CacheBean cacheBean) throws Exception {
                    return Observable.create(new ObservableOnSubscribe<IData>() {
                        @Override
                        public void subscribe(@NonNull ObservableEmitter<IData> emitter) throws Exception {
                            if (cacheBean != CacheBean.NULL) {
                                emitter.onNext(cacheBean.getData());
                                if (CacheBuilder.CACHE_ONLY == cb.cache) {
                                    return;
                                } else if (CacheBuilder.CACHE_POWER == cb.cache) {
                                    if (!CacheUtil.myCache().checkCacheOverdue(cacheBean, cb.cacheOverdue)) {
                                        return;
                                    }
                                }
                            }
                            IData data = getRemoteData(callBack.getEntityClass());
                            emitter.onNext(data);
                            emitter.onComplete();
                        }
                    });
                }
            }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io());
        } else {
            observer = observer.flatMap(new Function<CacheBuilder,ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(@NonNull CacheBuilder builder) throws Exception {
                    return Observable.create(new ObservableOnSubscribe<IData>() {
                        @Override
                        public void subscribe(@NonNull ObservableEmitter<IData> emitter) throws Exception {
                            IData data = getRemoteData(callBack.getEntityClass());
                            emitter.onNext(data);
                            emitter.onComplete();
                        }
                    });
                }
            }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io());
        }
        observer.subscribe(new Observer<IData>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {

            }

            @Override
            public void onNext(@NonNull IData o) {
                if(callBack != null) {
                    if (o instanceof Failure) {
                        callBack.onFailure((Failure) o);
                    } else {
                        callBack.onSuccess(o);
                    }
                }
            }

            @Override
            public void onError(@NonNull Throwable e) {
                if (callBack != null) {
                    Failure response = new Failure(Failure.ERROR_CONNECT,e.getMessage());
                    callBack.onFailure(response);
                }
            }

            @Override
            public void onComplete() {

            }
        });
    }

    /**
     *
     * @param cls
     * @param <T>
     * @return
     */
    protected abstract <T extends IData> IData getRemoteData(Class<T> cls);
}
